home *** CD-ROM | disk | FTP | other *** search
- #import "SpinView.h"
-
- #import <libc.h>
- #import <math.h>
- #import <sys/time.h>
- #import <defaults/defaults.h>
-
- #import <dpsclient/dpsclient.h>
- #import <dpsclient/wraps.h>
-
- #import <appkit/Slider.h>
-
- /**********************************************************************/
-
- #define PI ( 3.1415926 )
-
- #define DEGtoRAD(deg) ( deg * PI/180.0 )
-
- #define LEFT ( 100 )
- #define RIGHT ( 101 )
- #define UP ( 102 )
- #define DOWN ( 103 )
-
- /**********************************************************************/
-
- // Looks like a set of defaults to me, how 'bout you?
-
- static NXDefaultsVector SpinDefaults =
- {
- { "Radius", "104" },
- { "TailLength", "95" },
- { "XIncrement", "1.0" },
- { "YIncrement", "2.5" },
- { "AngleIncrement", "38" },
- { "NumberOfSpinners", "4" },
- { NULL },
- };
-
- /**********************************************************************/
-
- // userPathData holds four endpoint coordinates for each line to draw.
- // The endpoint coordinates are calculated on the fly, in drawSpinners:.
- // userPathOps holds a moveto/lineto pair for each line that can be drawn.
- // Both of these are passed to DPSDoUserPath(), along with the other
- // neccessary arguments. See the method drawSpinners: for the call.
-
- static float userPathData[ 4*MAXNUMSPINS ];
-
- static char userPathOps[ ] =
- {
- dps_moveto, dps_lineto,
- dps_moveto, dps_lineto,
- dps_moveto, dps_lineto,
- dps_moveto, dps_lineto,
- dps_moveto, dps_lineto,
- dps_moveto, dps_lineto,
- dps_moveto, dps_lineto,
- dps_moveto, dps_lineto,
- dps_moveto, dps_lineto,
- dps_moveto, dps_lineto,
- dps_moveto, dps_lineto,
- dps_moveto, dps_lineto,
- dps_moveto, dps_lineto,
- dps_moveto, dps_lineto,
- dps_moveto, dps_lineto,
- dps_moveto, dps_lineto,
- dps_moveto, dps_lineto,
- dps_moveto, dps_lineto,
- dps_moveto, dps_lineto,
- dps_moveto, dps_lineto
- };
-
- static float Sines[ 91 ]; // Table of sines. Filled in initFrame:
-
- static float SinRad[ 91 ]; // Table of (sines * current radius).
- // Filled in setStartPoints.
-
- static char tnum[ 20 ]; // Used to modify defaults, if they
- // need to be adjusted in the database.
-
- /**********************************************************************/
-
- @implementation SpinView
-
- /**********************************************************************/
-
- - (const char *) windowTitle
- {
- return ( const char * ) "Larrys Wild Spinners";
- }
-
- /**********************************************************************/
-
- - ( void ) getAngleInc
- {
- // Gets the current angle increment from the defaults database.
- // Checks to make sure the value found is within the range delimited
- // by MAXANGLEINC and MINANGLEINC. If the value is out of range it
- // is reset to the nearest inbounds value.
-
- CurAngleInc = atoi( NXGetDefaultValue( OWNER, "AngleIncrement" ) );
-
- if( CurAngleInc > MAXANGLEINC )
- {
- sprintf( tnum, "%3d", MAXANGLEINC );
- NXWriteDefault( OWNER, "AngleIncrement", tnum );
- CurAngleInc = MAXANGLEINC;
- }
- else if( CurAngleInc < MINANGLEINC )
- {
- sprintf( tnum, "%3d", MINANGLEINC );
- NXWriteDefault( OWNER, "AngleIncrement", tnum );
- CurAngleInc = MINANGLEINC;
- }
- }
-
- /**********************************************************************/
-
- - ( void ) getNumSpinners
- {
- // Gets the current number of spinners from the defaults database.
- // Checks to make sure the value found is within the range delimited
- // by MAXNUMSPINS and MINNUMSPINS. If the value is out of range it
- // is reset to the nearest inbounds value.
-
- CurNumSpins = atoi( NXGetDefaultValue( OWNER, "NumberOfSpinners" ) );
-
- if( CurNumSpins > MAXNUMSPINS )
- {
- sprintf( tnum, "%2d", MAXNUMSPINS );
- NXWriteDefault( OWNER, "NumberOfSpinners", tnum );
- CurNumSpins = MAXNUMSPINS;
- }
- else if( CurNumSpins < MINNUMSPINS )
- {
- sprintf( tnum, "%2d", MINNUMSPINS );
- NXWriteDefault( OWNER, "NumberOfSpinners", tnum );
- CurNumSpins = MINNUMSPINS;
- }
- }
-
- /**********************************************************************/
-
- - ( void ) getRadius
- {
- // Gets the current circle radius from the defaults database.
- // Checks to make sure the value found is within the range delimited
- // by MAXRADIUS and MINRADIUS. If the value is out of range it
- // is reset to the nearest inbounds value.
-
- CurRadius = atoi( NXGetDefaultValue( OWNER, "Radius" ) );
-
- if( CurRadius > MAXRADIUS )
- {
- sprintf( tnum, "%3d", MAXRADIUS );
- NXWriteDefault( OWNER, "Radius", tnum );
- CurRadius = MAXRADIUS;
- }
- else if( CurRadius < MINRADIUS )
- {
- sprintf( tnum, "%3d", MINRADIUS );
- NXWriteDefault( OWNER, "Radius", tnum );
- CurRadius = MINRADIUS;
- }
- }
-
- /**********************************************************************/
-
- - ( void ) getTailLength
- {
- // Gets the current tail length from the defaults database.
- // Checks to make sure the value found is within the range delimited
- // by MAXTAILLEN and MINTAILLEN. If the value is out of range it
- // is reset to the nearest inbounds value.
-
- CurTailLen = atoi( NXGetDefaultValue( OWNER, "TailLength" ) );
-
- if( CurTailLen > MAXTAILLEN )
- {
- sprintf( tnum, "%3d", MAXTAILLEN );
- NXWriteDefault( OWNER, "TailLength", tnum );
- CurTailLen = MAXTAILLEN;
- }
- else if( CurTailLen < MINTAILLEN )
- {
- sprintf( tnum, "%3d", MINTAILLEN );
- NXWriteDefault( OWNER, "TailLength", tnum );
- CurTailLen = MINTAILLEN;
- }
- }
-
- /**********************************************************************/
-
- - ( void ) getXIncrement
- {
- // Gets the current X increment from the defaults database.
- // Checks to make sure the value found is within the range delimited
- // by MAXXINC and MINXINC. If the value is out of range it
- // is reset to the nearest inbounds value.
-
- CurXInc = atof( NXGetDefaultValue( OWNER, "XIncrement" ) );
-
- if( CurXInc > MAXXINC )
- {
- sprintf( tnum, "%7.3f", MAXXINC );
- NXWriteDefault( OWNER, "XIncrement", tnum );
- CurXInc = MAXXINC;
- }
- else if( CurXInc < MINXINC )
- {
- sprintf( tnum, "%7.3f", MINXINC );
- NXWriteDefault( OWNER, "XIncrement", tnum );
- CurXInc = MINXINC;
- }
- }
-
- /**********************************************************************/
-
- - ( void ) getYIncrement
- {
- // Gets the current Y increment from the defaults database.
- // Checks to make sure the value found is within the range delimited
- // by MAXYINC and MINYINC. If the value is out of range it
- // is reset to the nearest inbounds value.
-
- CurYInc = atof( NXGetDefaultValue( OWNER, "YIncrement" ) );
-
- if( CurYInc > MAXYINC )
- {
- sprintf( tnum, "%7.3f", MAXYINC );
- NXWriteDefault( OWNER, "YIncrement", tnum );
- CurYInc = MAXYINC;
- }
- else if( CurYInc < MINYINC )
- {
- sprintf( tnum, "%7.3f", MINYINC );
- NXWriteDefault( OWNER, "YIncrement", tnum );
- CurYInc = MINYINC;
- }
- }
-
- /**********************************************************************/
-
- - initFrame : ( const NXRect * ) frameRect
- {
- // How many miscellaneous setup things can you
- // put into a single method, geez!
-
- struct timeval tp;
- struct timezone tzp;
- int i;
-
- [ super initFrame : frameRect ];
-
- [ self setOpaque : YES ];
- [ self setClipping : NO ];
-
- NXRegisterDefaults( OWNER, SpinDefaults );
-
- [ self getNumSpinners ];
- [ self getRadius ];
- [ self getAngleInc ];
- [ self getTailLength ];
- [ self getXIncrement ];
- [ self getYIncrement ];
-
- PSsetlinewidth( 0.15 );
-
- gettimeofday( &tp, &tzp );
- srandom( ( int ) tp.tv_sec + tp.tv_usec );
-
- for( i = 0; i < 91; ++i )
- Sines[ i ] = sin( DEGtoRAD(i) ); // Fill in sines table.
-
- [ self resetSpinners ];
-
- return self;
- }
-
- /**********************************************************************/
-
- - newWindow
- {
- [ self resetSpinners ];
-
- return self;
- }
-
- /**********************************************************************/
-
- - sizeTo : ( NXCoord ) width : ( NXCoord ) height
- {
- [ super sizeTo : width : height ];
-
- [ self resetSpinners ];
-
- return self;
- }
-
- /**********************************************************************/
-
- - ( void ) setStartPoints
- {
- int i;
-
- for( i = 0; i < CurNumSpins; ++i )
- {
- headSpin[i].x = tailSpin[i].x = random() % ( (int) bounds.size.width);
- headSpin[i].y = tailSpin[i].y = random() % ( (int) bounds.size.height);
- }
-
- // Reset the color cycle.
-
- r = 0;
- g = ( 2 * PI ) / 3;
-
- // Everytime the current radius changes the SinRad[] table and the
- // bounding box need to be updated. These should probably be done
- // in the setRadius: method, but it's so fast I don't think it matters.
-
- for( i = 0; i < 91; ++i )
- SinRad[ i ] = CurRadius * Sines[ i ];
-
- // Setting the bounding box this way gives the spinners a more consistent
- // feel. When there is only one spinner displayed the speed of the spinner
- // appears near the speed of having 20 spinners on the screen. Using a
- // consistent bounding box has a lot to do with it.
- // The 30 is a fudge factor, I guess I should figure out the real value
- // at some point.
-
- Bbox[ 0 ] = bounds.origin.x - ( CurRadius + 30 );
- Bbox[ 1 ] = bounds.origin.y - ( CurRadius + 30 );
- Bbox[ 2 ] = bounds.origin.x + bounds.size.width + ( CurRadius + 30 );
- Bbox[ 3 ] = bounds.origin.y + bounds.size.height + ( CurRadius + 30 );
-
- }
-
- /**********************************************************************/
-
- - ( void ) resetSpinners
- {
- // This method realigns the head and tail spinner data structures.
- // Each time a control is adjusted this method is called. It is much
- // simpler to reset everything after a control is adjusted than
- // it is to figure out how to align things on the fly.
-
- SPINNER *hs;
- SPINNER *ts;
- int iMod2;
- int i;
-
- [ self setStartPoints ];
-
- hs = headSpin; // Moving pointers through the arrays is a lot faster.
- ts = tailSpin;
-
- for( i = 0; i < CurNumSpins; ++i, ++hs, ++ts )
- {
- hs->a = ts->a = random() % 360;
- hs->ix = ts->ix = CurXInc;
- hs->iy = ts->iy = CurYInc;
-
- iMod2 = i % 2;
- hs->dx = ts->dx = ( ( iMod2 ) ? RIGHT : LEFT );
- hs->dy = ts->dy = ( ( iMod2 ) ? DOWN : UP );
- }
-
- if( tailSlider )
- CurTailLen = [ tailSlider intValue ];
- }
-
- /**********************************************************************/
-
- - ( void ) moveSpinner : ( SPINNER * ) spin
- {
- spin->a = ( spin->a + CurAngleInc ) % 360;
-
- if( spin->x >= bounds.size.width )
- spin->dx = LEFT;
- else if( spin->x <= 0 )
- spin->dx = RIGHT;
-
- spin->x += ( spin->dx == RIGHT ) ? spin->ix : -spin->ix;
-
- if( spin->y >= bounds.size.height )
- spin->dy = DOWN;
- else if( spin->y <= 0 )
- spin->dy = UP;
-
- spin->y += ( spin->dy == UP ) ? spin->iy : -spin->iy;
- }
-
- /**********************************************************************/
-
- - ( void ) drawSpinners : ( SPINNER * ) spin
- {
- // I know this looks a little complicated, but it really
- // just builds a user path. It fills the userPathData[] array
- // with enough endpoints to draw CurNumSpins lines. Once userPathData[]
- // is filled its passed to DPSDoUserPath(), along with the count of
- // points in the array.
-
- float offset1;
- float offset2;
- int i, j;
-
- for( i = 0, j = 0; i < CurNumSpins; ++i, ++spin )
- {
- if( spin->a >= 270 )
- {
- offset1 = -SinRad[ 360 - spin->a ];
- offset2 = SinRad[ spin->a - 270 ];
- }
- else if( spin->a >= 180 )
- {
- offset1 = -SinRad[ spin->a - 180 ];
- offset2 = -SinRad[ 270 - spin->a ];
- }
- else if( spin->a >= 90 )
- {
- offset1 = SinRad[ 180 - spin->a ];
- offset2 = -SinRad[ spin->a - 90 ];
- }
- else
- {
- offset1 = SinRad[ spin->a ];
- offset2 = SinRad[ 90 - spin->a ];
- }
-
- userPathData[ j++ ] = spin->x + offset2;
- userPathData[ j++ ] = spin->y + offset1;
- userPathData[ j++ ] = spin->x - offset2;
- userPathData[ j++ ] = spin->y - offset1;
-
- [ self moveSpinner : spin ];
- }
-
- DPSDoUserPath( userPathData, j, dps_float, userPathOps,
- CurNumSpins*2, Bbox, dps_ustroke );
- }
-
- /**********************************************************************/
-
- - oneStep
- {
- if( CurTailLen-- <= 0 )
- {
- PSsetrgbcolor( 0.0, 0.0, 0.0 );
-
- [ self drawSpinners : tailSpin ];
- }
-
- // PSsetgray( NX_WHITE ); // Used only for testing.
-
- r -= ( r > 2 * PI ) ? 2 * PI : -0.008;
- g -= ( g > 2 * PI ) ? 2 * PI : -0.02;
- b -= ( b > 2 * PI ) ? 2 * PI : -0.01;
-
- PSsetrgbcolor( ( cos( r ) + 1.0 ) * .5,
- ( cos( g ) + 1.0 ) * .5,
- ( cos( b ) + 1.0 ) * .5 );
-
- [ self drawSpinners : headSpin ];
-
- return self;
- }
-
- /**********************************************************************/
-
- - drawSelf : ( NXRect * ) rect : ( int ) count
- {
- if (!rect || !count)
- return self;
-
- PSsetgray( NX_BLACK );
-
- NXRectFill( rect );
-
- return self;
-
- }
-
- /**********************************************************************/
-
- @end
-